package com.tim.android.widget.cardview;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;

public class CardViewContainer extends RelativeLayout {
	
	private int mCardWidth;
	private int mCardOriginX;
	private int mCardOriginY;
	private int mIndex = 0;
	private float mTouchX;
	private float mStartTouchX;
	
	private View mFrontView;
	private List<View> mCardList = new ArrayList<View>();
	
	private TranslateAnimation mAnimation;
	
	private OnSwitchCardListener mListener;
	
	private long mLastTime = 0;
	
	public CardViewContainer(Context context) {
		super(context);
	}
	
	public CardViewContainer(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public CardViewContainer(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}
	
	private void addCardViews(List<? extends View> cardViews, boolean addToUI) {
		if(cardViews != null && cardViews.size() > 0) {
			int index = 0;
			for(View card : cardViews) {
				if(card != null) {
					if(addToUI) {
						addView(card);
					}
					mCardList.add(card);
					if(index++ < cardViews.size() - 2) {
						card.setVisibility(View.INVISIBLE);
					}
				}
			}
			invalidate();
		}
	}
	
	public void addCardViews(List<? extends View> cardViews) {
		addCardViews(cardViews, true);
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		int childCount = getChildCount();
		if(childCount > 0 && mCardList.size() == 0) {
			List<View> children = new ArrayList<View>(childCount);
			for(int i = 0; i < childCount; i++) {
				View view = getChildAt(i);
				children.add(view);
			}
			addCardViews(children, false);
			mCardOriginX = children.get(0).getLeft();
			mCardOriginY = children.get(0).getTop();
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		float x = event.getX();
		
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				final long currentTime = System.currentTimeMillis();
				if(currentTime - mLastTime < 300) {
					return true;
				}
				mLastTime = currentTime;
				if(mCardList.size() > 0) {
					mFrontView = mCardList.get(mCardList.size() - 1);
					Boolean scrolling = (Boolean) mFrontView.getTag();
					if(scrolling == null || !scrolling.booleanValue()) {
						mCardWidth = mFrontView.getWidth();
						mTouchX = x;
						mStartTouchX = x;
					}
					else {
						mFrontView = null;
					}
				}
				break;
				
			case MotionEvent.ACTION_MOVE:
				if(mFrontView != null) {
					int dx = (int) (mTouchX - x);
					int l = mFrontView.getLeft() - dx;
					int t = mFrontView.getTop();
					int r = l + mFrontView.getWidth();
					int b = mFrontView.getBottom();
					mFrontView.layout(l, t, r, b);
					if(Math.abs(mStartTouchX - x) > (mCardWidth / 3)) {
						animateToDefaultPosition(true);
						mFrontView = null;
					}
					mTouchX = x;
				}
				break;
				
			case MotionEvent.ACTION_UP:
			case MotionEvent.ACTION_CANCEL:
				if(mFrontView != null) {
					animateToDefaultPosition(false);
					mFrontView = null;
				}
				return false;
		}
		return true;
	}
	
	private void animateToDefaultPosition(boolean switchCard) {
		int l = mFrontView.getLeft();
		int t = mFrontView.getTop();
		int r = l + mFrontView.getWidth();
		int b = t + mFrontView.getHeight();
		if(switchCard) {
			mIndex = (++mIndex) > (mCardList.size() - 1) ? 0 : mIndex;
			t += (mCardWidth / 3);
			b = t + mFrontView.getHeight();
			mCardList.remove(mCardList.size() - 1);
			mCardList.add(0, mFrontView);
			int size = mCardList.size();
			for(int i = 0; i < size; i ++) {
				View view = mCardList.get(i);
				if(i > size - 3) {
					view.setVisibility(View.VISIBLE);
				}
				view.bringToFront();
			}
			mFrontView.layout(l, t, r, b);
			if(mListener != null) {
				mListener.onSwitchCard();
			}
		}
		mAnimation = new TranslateAnimation(switchCard, l, mCardOriginX, t, mCardOriginY);
		mAnimation.start();
	}
	
	private class TranslateAnimation extends Thread {

		public int mFromX, mToX, mFromY, mToY;
		private View mView;
		
		private boolean mSwitchCard;
		
		public TranslateAnimation(boolean switchCard, int fromX, int toX, int fromY, int toY) {
			mSwitchCard = switchCard;
			this.mFromX = fromX;
			this.mToX = toX;
			this.mFromY = fromY;
			this.mToY = toY;
			mView = mFrontView;
		}

		@Override
		public void run() {
			mView.setTag(true);
			int dx = mFromX < mToX ? 5 : -5;
			int dy = 0;
			final boolean switchCard = mSwitchCard;
			while(mFromX != mToX || mFromY != mToY) {
				mFromX += dx;
				if(Math.abs(mToX - mFromX) < 5) {
					mFromX = mToX;
				}
				if(switchCard) {
					dy = mFromY - 5;
					mFromY = Math.max(dy, mToY);
				}
				mView.post(layoutOnUIThread);
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			mView.setTag(false);
			if(switchCard) {
				mView.post(setInVisibleOnUIThread);
			}
		}
		
		private final Runnable layoutOnUIThread = new Runnable() {
			
			@Override
			public void run() {
				mView.layout(mFromX, mFromY, 
						mFromX + mView.getWidth(), mFromY + mView.getHeight());
				mView.invalidate();
			}
		};
		
		private final Runnable setInVisibleOnUIThread = new Runnable() {
			
			@Override
			public void run() {
				mView.setVisibility(View.INVISIBLE);
			}
		};
	}
	
	public int getCardViewSize() {
		return mCardList.size();
	}
	
	public int getIndex() {
		return mIndex;
	}
	
	public void setOnSwitchCardListener(OnSwitchCardListener l) {
		mListener = l;
	}
	
	public static interface OnSwitchCardListener {
		void onSwitchCard();
	}
}
